home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / StormMesa / src-glut / glut_dstr.c < prev    next >
C/C++ Source or Header  |  1998-12-15  |  46KB  |  1,628 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1997. */
  3.  
  4. /* This program is freely distributable without licensing fees
  5.    and is provided without guarantee or warrantee expressed or
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. #include <assert.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "glutint.h"
  13.  
  14. /* glxcaps matches the criteria macros listed in glutint.h, but
  15.    only list the first set (those that correspond to GLX visual
  16.    attributes). */
  17. static int glxcap[NUM_GLXCAPS] =
  18. {
  19.   GLX_RGBA,
  20.   GLX_BUFFER_SIZE,
  21.   GLX_DOUBLEBUFFER,
  22.   GLX_STEREO,
  23.   GLX_AUX_BUFFERS,
  24.   GLX_RED_SIZE,
  25.   GLX_GREEN_SIZE,
  26.   GLX_BLUE_SIZE,
  27.   GLX_ALPHA_SIZE,
  28.   GLX_DEPTH_SIZE,
  29.   GLX_STENCIL_SIZE,
  30.   GLX_ACCUM_RED_SIZE,
  31.   GLX_ACCUM_GREEN_SIZE,
  32.   GLX_ACCUM_BLUE_SIZE,
  33.   GLX_ACCUM_ALPHA_SIZE,
  34.   GLX_LEVEL,
  35. };
  36.  
  37. #ifdef TEST
  38.  
  39. #if !defined(_WIN32)
  40. char *__glutProgramName = "dstr";
  41. Display *__glutDisplay;
  42. int __glutScreen;
  43. XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
  44.   Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) = NULL;
  45. char *__glutDisplayString = NULL;
  46. #endif
  47. static int verbose = 0;
  48.  
  49. static char *compstr[] =
  50. {
  51.   "none", "=", "!=", "<=", ">=", ">", "<", "~"
  52. };
  53. static char *capstr[] =
  54. {
  55.   "rgba", "bufsize", "double", "stereo", "auxbufs", "red", "green", "blue", "alpha",
  56.   "depth", "stencil", "acred", "acgreen", "acblue", "acalpha", "level", "xvisual",
  57.   "transparent", "samples", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
  58.   "xtruecolor", "xdirectcolor", "slow", "conformant", "num"
  59. };
  60.  
  61. static void
  62. printCriteria(Criterion * criteria, int ncriteria)
  63. {
  64.   int i;
  65.   printf("Criteria: %d\n", ncriteria);
  66.   for (i = 0; i < ncriteria; i++) {
  67.     printf("  %s %s %d\n",
  68.       capstr[criteria[i].capability],
  69.       compstr[criteria[i].comparison],
  70.       criteria[i].value);
  71.   }
  72. }
  73.  
  74. #endif /* TEST */
  75.  
  76. static int isMesaGLX = -1;
  77.  
  78. static int
  79. determineMesaGLX(void)
  80. {
  81. #ifdef GLX_VERSION_1_1
  82.   const char *vendor, *version, *ch;
  83.  
  84.   vendor = glXGetClientString(__glutDisplay, GLX_VENDOR);
  85.   if (!strcmp(vendor, "Brian Paul")) {
  86.     version = glXGetClientString(__glutDisplay, GLX_VERSION);
  87.     for (ch = version; *ch != ' ' && *ch != '\0'; ch++);
  88.     for (; *ch == ' ' && *ch != '\0'; ch++);
  89.  
  90. #define MESA_NAME "Mesa "  /* Trailing space is intentional. */
  91.  
  92.     if (!strncmp(MESA_NAME, ch, sizeof(MESA_NAME) - 1)) {
  93.       return 1;
  94.     }
  95.   }
  96. #else
  97.   /* Recent versions for Mesa should support GLX 1.1 and
  98.      therefore glXGetClientString.  If we get into this case,
  99.      we would be compiling against a true OpenGL not supporting
  100.      GLX 1.1, and the resulting compiled library won't work well 
  101.      with Mesa then. */
  102. #endif
  103.   return 0;
  104. }
  105.  
  106. static XVisualInfo **
  107. getMesaVisualList(int *n)
  108. {
  109.   XVisualInfo **vlist, *vinfo;
  110.   int attribs[23];
  111.   int i, x, cnt;
  112.  
  113.   vlist = (XVisualInfo **) malloc((32 + 16) * sizeof(XVisualInfo *));
  114.   if (!vlist)
  115.     __glutFatalError("out of memory.");
  116.  
  117.   cnt = 0;
  118.   for (i = 0; i < 32; i++) {
  119.     x = 0;
  120.     attribs[x] = GLX_RGBA;
  121.     x++;
  122.     attribs[x] = GLX_RED_SIZE;
  123.     x++;
  124.     attribs[x] = 1;
  125.     x++;
  126.     attribs[x] = GLX_GREEN_SIZE;
  127.     x++;
  128.     attribs[x] = 1;
  129.     x++;
  130.     attribs[x] = GLX_BLUE_SIZE;
  131.     x++;
  132.     attribs[x] = 1;
  133.     x++;
  134.     if (i & 1) {
  135.       attribs[x] = GLX_DEPTH_SIZE;
  136.       x++;
  137.       attribs[x] = 1;
  138.       x++;
  139.     }
  140.     if (i & 2) {
  141.       attribs[x] = GLX_STENCIL_SIZE;
  142.       x++;
  143.       attribs[x] = 1;
  144.       x++;
  145.     }
  146.     if (i & 4) {
  147.       attribs[x] = GLX_ACCUM_RED_SIZE;
  148.       x++;
  149.       attribs[x] = 1;
  150.       x++;
  151.       attribs[x] = GLX_ACCUM_GREEN_SIZE;
  152.       x++;
  153.       attribs[x] = 1;
  154.       x++;
  155.       attribs[x] = GLX_ACCUM_BLUE_SIZE;
  156.       x++;
  157.       attribs[x] = 1;
  158.       x++;
  159.     }
  160.     if (i & 8) {
  161.       attribs[x] = GLX_ALPHA_SIZE;
  162.       x++;
  163.       attribs[x] = 1;
  164.       x++;
  165.       if (i & 4) {
  166.         attribs[x] = GLX_ACCUM_ALPHA_SIZE;
  167.         x++;
  168.         attribs[x] = 1;
  169.         x++;
  170.       }
  171.     }
  172.     if (i & 16) {
  173.       attribs[x] = GLX_DOUBLEBUFFER;
  174.       x++;
  175.     }
  176.     attribs[x] = None;
  177.     x++;
  178.     assert(x <= sizeof(attribs) / sizeof(attribs[0]));
  179.     vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
  180.     if (vinfo) {
  181.       vlist[cnt] = vinfo;
  182.       cnt++;
  183.     }
  184.   }
  185.   for (i = 0; i < 16; i++) {
  186.     x = 0;
  187.     if (i & 1) {
  188.       attribs[x] = GLX_DEPTH_SIZE;
  189.       x++;
  190.       attribs[x] = 1;
  191.       x++;
  192.     }
  193.     if (i & 2) {
  194.       attribs[x] = GLX_STENCIL_SIZE;
  195.       x++;
  196.       attribs[x] = 1;
  197.       x++;
  198.     }
  199.     if (i & 4) {
  200.       attribs[x] = GLX_DOUBLEBUFFER;
  201.       x++;
  202.     }
  203.     if (i & 8) {
  204.       attribs[x] = GLX_LEVEL;
  205.       x++;
  206.       attribs[x] = 1;
  207.       x++;
  208. #if defined(GLX_TRANSPARENT_TYPE_EXT) && defined(GLX_TRANSPARENT_INDEX_EXT)
  209.       attribs[x] = GLX_TRANSPARENT_TYPE_EXT;
  210.       x++;
  211.       attribs[x] = GLX_TRANSPARENT_INDEX_EXT;
  212.       x++;
  213. #endif
  214.     }
  215.     attribs[x] = None;
  216.     x++;
  217.     assert(x <= sizeof(attribs) / sizeof(attribs[0]));
  218.     vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
  219.     if (vinfo) {
  220.       vlist[cnt] = vinfo;
  221.       cnt++;
  222.     }
  223.   }
  224.  
  225.   *n = cnt;
  226.   return vlist;
  227. }
  228.  
  229. static FrameBufferMode *
  230. loadVisuals(int *nitems_return)
  231. {
  232.   XVisualInfo *vinfo, **vlist, template;
  233.   FrameBufferMode *fbmodes, *mode;
  234.   int n, i, j, rc, glcapable;
  235. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  236.   int multisample;
  237. #endif
  238. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
  239.   int visual_info;
  240. #endif
  241. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  242.   int visual_rating;
  243. #endif
  244. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  245.   int fbconfig;
  246. #endif
  247.  
  248.   isMesaGLX = determineMesaGLX();
  249.   if (isMesaGLX) {
  250.     vlist = getMesaVisualList(&n);
  251.   } else {
  252. #if !defined(_WIN32)
  253.     template.screen = __glutScreen;
  254.     vinfo = XGetVisualInfo(__glutDisplay, VisualScreenMask, &template, &n);
  255. #else
  256.     vinfo = XGetVisualInfo(__glutDisplay, 0, &template, &n);
  257. #endif
  258.     if (vinfo == NULL) {
  259.       *nitems_return = 0;
  260.       return NULL;
  261.     }
  262.     assert(n > 0);
  263.  
  264.     /* Make an array of XVisualInfo* pointers to help the Mesa
  265.        case because each glXChooseVisual call returns a
  266.        distinct XVisualInfo*, not a handy array like
  267.        XGetVisualInfo.  (Mesa expects us to return the _exact_
  268.        pointer returned by glXChooseVisual so we could not just
  269.        copy the returned structure.) */
  270.     vlist = (XVisualInfo **) malloc(n * sizeof(XVisualInfo *));
  271.     if (!vlist)
  272.       __glutFatalError("out of memory.");
  273.     for (i = 0; i < n; i++) {
  274.       vlist[i] = &vinfo[i];
  275.     }
  276.   }
  277.  
  278. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  279.   multisample = __glutIsSupportedByGLX("GLX_SGIS_multisample");
  280. #endif
  281. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
  282.   visual_info = __glutIsSupportedByGLX("GLX_EXT_visual_info");
  283. #endif
  284. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  285.   visual_rating = __glutIsSupportedByGLX("GLX_EXT_visual_rating");
  286. #endif
  287. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  288.   fbconfig = __glutIsSupportedByGLX("GLX_SGIX_fbconfig");
  289. #endif
  290.  
  291.   fbmodes = (FrameBufferMode *) malloc(n * sizeof(FrameBufferMode));
  292.   if (fbmodes == NULL) {
  293.     *nitems_return = -1;
  294.     return NULL;
  295.   }
  296.   for (i = 0; i < n; i++) {
  297.     mode = &fbmodes[i];
  298.     mode->vi = vlist[i];
  299. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  300.     mode->fbc = NULL;
  301. #endif
  302.     rc = glXGetConfig(__glutDisplay, vlist[i], GLX_USE_GL, &glcapable);
  303.     if (rc == 0 && glcapable) {
  304.       mode->valid = 1;  /* Assume the best until proven
  305.                            otherwise. */
  306.       for (j = 0; j < NUM_GLXCAPS; j++) {
  307.         rc = glXGetConfig(__glutDisplay, vlist[i], glxcap[j], &mode->cap[j]);
  308.         if (rc != 0) {
  309.           mode->valid = 0;
  310.         }
  311.       }
  312. #if defined(_WIN32)
  313.       mode->cap[XVISUAL] = ChoosePixelFormat(XHDC, vlist[i]);
  314. #else
  315.       mode->cap[XVISUAL] = (int) vlist[i]->visualid;
  316. #endif
  317.       mode->cap[XSTATICGRAY] = 0;
  318.       mode->cap[XGRAYSCALE] = 0;
  319.       mode->cap[XSTATICCOLOR] = 0;
  320.       mode->cap[XPSEUDOCOLOR] = 0;
  321.       mode->cap[XTRUECOLOR] = 0;
  322.       mode->cap[XDIRECTCOLOR] = 0;
  323. #if !defined(_WIN32)
  324. #if defined(__cplusplus) || defined(c_plusplus)
  325.       switch (vlist[i]->c_class) {
  326. #else
  327.       switch (vlist[i]->class) {
  328. #endif
  329.       case StaticGray:
  330.         mode->cap[XSTATICGRAY] = 1;
  331.         break;
  332.       case GrayScale:
  333.         mode->cap[XGRAYSCALE] = 1;
  334.         break;
  335.       case StaticColor:
  336.         mode->cap[XSTATICCOLOR] = 1;
  337.         break;
  338.       case PseudoColor:
  339.         mode->cap[XPSEUDOCOLOR] = 1;
  340.         break;
  341.       case TrueColor:
  342.         mode->cap[XTRUECOLOR] = 1;
  343.         break;
  344.       case DirectColor:
  345.         mode->cap[XDIRECTCOLOR] = 1;
  346.         break;
  347.       }
  348. #endif
  349. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  350.       if (visual_rating) {
  351.         int rating;
  352.  
  353. /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
  354.    564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
  355.    in <GL/glx.h> despite claiming to support
  356.    GLX_EXT_visual_rating. */
  357. #ifndef GLX_VISUAL_CAVEAT_EXT
  358. #define GLX_VISUAL_CAVEAT_EXT 0x20
  359. #endif
  360.  
  361.         rc = glXGetConfig(__glutDisplay,
  362.       vlist[i], GLX_VISUAL_CAVEAT_EXT, &rating);
  363.         if (rc != 0) {
  364.           mode->cap[SLOW] = 0;
  365.           mode->cap[CONFORMANT] = 1;
  366.         } else {
  367.           switch (rating) {
  368.           case GLX_SLOW_VISUAL_EXT:
  369.             mode->cap[SLOW] = 1;
  370.             mode->cap[CONFORMANT] = 1;
  371.             break;
  372.  
  373. /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
  374.    properly defined in /usr/include/GL/glxtokens.h */
  375. #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
  376. #define GLX_NON_CONFORMANT_VISUAL_EXT   0x800D
  377. #endif
  378.  
  379.           case GLX_NON_CONFORMANT_VISUAL_EXT:
  380.             mode->cap[SLOW] = 0;
  381.             mode->cap[CONFORMANT] = 0;
  382.             break;
  383.           case GLX_NONE_EXT:
  384.           default:     /* XXX Hopefully this is a good default
  385.                            assumption. */
  386.             mode->cap[SLOW] = 0;
  387.             mode->cap[CONFORMANT] = 1;
  388.             break;
  389.           }
  390.         }
  391.       } else {
  392.         mode->cap[TRANSPARENT] = 0;
  393.       }
  394. #else
  395.       mode->cap[SLOW] = 0;
  396.       mode->cap[CONFORMANT] = 1;
  397. #endif
  398. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
  399.       if (visual_info) {
  400.         int transparent;
  401.  
  402. /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
  403.    564 for Alpha did not properly define
  404.    GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
  405.    support GLX_EXT_visual_info. */
  406. #ifndef GLX_TRANSPARENT_TYPE_EXT
  407. #define GLX_TRANSPARENT_TYPE_EXT 0x23
  408. #endif
  409.  
  410.         rc = glXGetConfig(__glutDisplay,
  411.           vlist[i], GLX_TRANSPARENT_TYPE_EXT, &transparent);
  412.         if (rc != 0) {
  413.           mode->cap[TRANSPARENT] = 0;
  414.         } else {
  415.           mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
  416.         }
  417.       } else {
  418.         mode->cap[TRANSPARENT] = 0;
  419.       }
  420. #else
  421.       mode->cap[TRANSPARENT] = 0;
  422. #endif
  423. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  424.       if (multisample) {
  425.         rc = glXGetConfig(__glutDisplay,
  426.       vlist[i], GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
  427.         if (rc != 0) {
  428.           mode->cap[SAMPLES] = 0;
  429.         }
  430.       } else {
  431.         mode->cap[SAMPLES] = 0;
  432.       }
  433. #else
  434.       mode->cap[SAMPLES] = 0;
  435. #endif
  436.     } else {
  437. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  438.       if (fbconfig) {
  439.         GLXFBConfigSGIX fbc;
  440.         int fbconfigID, drawType, renderType;
  441.  
  442.         fbc = glXGetFBConfigFromVisualSGIX(__glutDisplay, vlist[i]);
  443.         if (fbc) {
  444.           rc = glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
  445.         GLX_FBCONFIG_ID_SGIX, &fbconfigID);
  446.           if ((rc == 0) && (fbconfigID != None)) {
  447.             rc = glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
  448.           GLX_DRAWABLE_TYPE_SGIX, &drawType);
  449.             if ((rc == 0) && (drawType & GLX_WINDOW_BIT_SGIX)) {
  450.               rc = glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
  451.             GLX_RENDER_TYPE_SGIX, &renderType);
  452.               if ((rc == 0) && (renderType & GLX_RGBA_BIT_SGIX)) {
  453.                 mode->fbc = fbc;
  454.                 mode->valid = 1;  /* Assume the best until
  455.                                      proven otherwise. */
  456.  
  457.         assert(glxcap[0] == GLX_RGBA);
  458.                 mode->cap[0] = 1;
  459.  
  460.                 /* Start with "j = 1" to skip the GLX_RGBA attribute. */
  461.                 for (j = 1; j < NUM_GLXCAPS; j++) {
  462.                   rc = glXGetFBConfigAttribSGIX(__glutDisplay,
  463.             fbc, glxcap[j], &mode->cap[j]);
  464.                   if (rc != 0) {
  465.                     mode->valid = 0;
  466.                   }
  467.                 }
  468.  
  469.                 mode->cap[XVISUAL] = (int) vlist[i]->visualid;
  470.                 mode->cap[XSTATICGRAY] = 0;
  471.                 mode->cap[XGRAYSCALE] = 0;
  472.                 mode->cap[XSTATICCOLOR] = 0;
  473.                 mode->cap[XPSEUDOCOLOR] = 0;
  474.                 mode->cap[XTRUECOLOR] = 0;
  475.                 mode->cap[XDIRECTCOLOR] = 0;
  476. #if defined(__cplusplus) || defined(c_plusplus)
  477.                 switch (vlist[i]->c_class) {
  478. #else
  479.                 switch (vlist[i]->class) {
  480. #endif
  481.                 case StaticGray:
  482.                   mode->cap[XSTATICGRAY] = 1;
  483.                   break;
  484.                 case GrayScale:
  485.                   mode->cap[XGRAYSCALE] = 1;
  486.                   break;
  487.                 case StaticColor:
  488.                   mode->cap[XSTATICCOLOR] = 1;
  489.                   break;
  490.                 case PseudoColor:
  491.                   mode->cap[XPSEUDOCOLOR] = 1;
  492.                   break;
  493.                 case TrueColor:
  494.                   mode->cap[XTRUECOLOR] = 1;
  495.                   break;
  496.                 case DirectColor:
  497.                   mode->cap[XDIRECTCOLOR] = 1;
  498.                   break;
  499.                 }
  500. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  501.                 if (visual_rating) {
  502.                   int rating;
  503.  
  504. /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
  505.    564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
  506.    in <GL/glx.h> despite claiming to support
  507.    GLX_EXT_visual_rating. */
  508. #ifndef GLX_VISUAL_CAVEAT_EXT
  509. #define GLX_VISUAL_CAVEAT_EXT 0x20
  510. #endif
  511.  
  512.                   rc = glXGetFBConfigAttribSGIX(__glutDisplay,
  513.             fbc, GLX_VISUAL_CAVEAT_EXT, &rating);
  514.                   if (rc != 0) {
  515.                     mode->cap[SLOW] = 0;
  516.                     mode->cap[CONFORMANT] = 1;
  517.                   } else {
  518.                     switch (rating) {
  519.                     case GLX_SLOW_VISUAL_EXT:
  520.                       mode->cap[SLOW] = 1;
  521.                       mode->cap[CONFORMANT] = 1;
  522.                       break;
  523.  
  524. /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
  525.    properly defined in /usr/include/GL/glxtokens.h */
  526. #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
  527. #define GLX_NON_CONFORMANT_VISUAL_EXT   0x800D
  528. #endif
  529.  
  530.                     case GLX_NON_CONFORMANT_VISUAL_EXT:
  531.                       mode->cap[SLOW] = 0;
  532.                       mode->cap[CONFORMANT] = 0;
  533.                       break;
  534.                     case GLX_NONE_EXT:
  535.                     default:  /* XXX Hopefully this is a good
  536.                                   default assumption. */
  537.                       mode->cap[SLOW] = 0;
  538.                       mode->cap[CONFORMANT] = 1;
  539.                       break;
  540.                     }
  541.                   }
  542.                 } else {
  543.                   mode->cap[TRANSPARENT] = 0;
  544.                 }
  545. #else
  546.                 mode->cap[SLOW] = 0;
  547.                 mode->cap[CONFORMANT] = 1;
  548. #endif
  549. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
  550.                 if (visual_info) {
  551.                   int transparent;
  552.  
  553. /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
  554.    564 for Alpha did not properly define
  555.    GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
  556.    support GLX_EXT_visual_info. */
  557. #ifndef GLX_TRANSPARENT_TYPE_EXT
  558. #define GLX_TRANSPARENT_TYPE_EXT 0x23
  559. #endif
  560.  
  561.                   rc = glXGetFBConfigAttribSGIX(__glutDisplay,
  562.             fbc, GLX_TRANSPARENT_TYPE_EXT, &transparent);
  563.                   if (rc != 0) {
  564.                     mode->cap[TRANSPARENT] = 0;
  565.                   } else {
  566.                     mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
  567.                   }
  568.                 } else {
  569.                   mode->cap[TRANSPARENT] = 0;
  570.                 }
  571. #else
  572.                 mode->cap[TRANSPARENT] = 0;
  573. #endif
  574. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  575.                 if (multisample) {
  576.                   rc = glXGetFBConfigAttribSGIX(__glutDisplay,
  577.             fbc, GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
  578.                   if (rc != 0) {
  579.                     mode->cap[SAMPLES] = 0;
  580.                   }
  581.                 } else {
  582.                   mode->cap[SAMPLES] = 0;
  583.                 }
  584. #else
  585.                 mode->cap[SAMPLES] = 0;
  586. #endif
  587.  
  588.               } else {
  589.                 /* Fbconfig is not RGBA; GLUT only uses RGBA
  590.                    FBconfigs. */
  591.                 /* XXX Code could be exteneded to handle color
  592.                    index FBconfigs, but seems a color index
  593.                    window-renderable FBconfig would also be
  594.                    advertised as an X visual. */
  595.                 mode->valid = 0;
  596.               }
  597.             } else {
  598.               /* Fbconfig does not support window rendering;
  599.                  not a valid FBconfig for GLUT windows. */
  600.               mode->valid = 0;
  601.             }
  602.           } else {
  603.             /* FBconfig ID is None (zero); not a valid
  604.                FBconfig. */
  605.             mode->valid = 0;
  606.           }
  607.         } else {
  608.           /* FBconfig ID is None (zero); not a valid FBconfig. */
  609.           mode->valid = 0;
  610.         }
  611.       } else {
  612.         /* No SGIX_fbconfig GLX sever implementation support. */
  613.         mode->valid = 0;
  614.       }
  615. #else
  616.       /* No SGIX_fbconfig GLX extension API support. */
  617.       mode->valid = 0;
  618. #endif
  619.     }
  620.   }
  621.  
  622.   free(vlist);
  623.   *nitems_return = n;
  624.   return fbmodes;
  625. }
  626.  
  627. static XVisualInfo *
  628. findMatch(FrameBufferMode * fbmodes, int nfbmodes,
  629.   Criterion * criteria, int ncriteria, void **fbc)
  630. {
  631.   FrameBufferMode *found;
  632.   int *bestScore, *thisScore;
  633.   int i, j, numok, result, worse, better;
  634.  
  635.   found = NULL;
  636.   numok = 1;            /* "num" capability is indexed from 1,
  637.                            not 0. */
  638.  
  639.   /* XXX alloca canidate. */
  640.   bestScore = (int *) malloc(ncriteria * sizeof(int));
  641.   if (!bestScore)
  642.     __glutFatalError("out of memory.");
  643.   for (j = 0; j < ncriteria; j++) {
  644.     /* Very negative number. */
  645.     bestScore[j] = -32768;
  646.   }
  647.  
  648.   /* XXX alloca canidate. */
  649.   thisScore = (int *) malloc(ncriteria * sizeof(int));
  650.   if (!thisScore)
  651.     __glutFatalError("out of memory.");
  652.  
  653.   for (i = 0; i < nfbmodes; i++) {
  654.     if (fbmodes[i].valid) {
  655. #ifdef TEST
  656. #if !defined(_WIN32)
  657.       if (verbose)
  658.         printf("Visual 0x%x\n", fbmodes[i].vi->visualid);
  659. #endif
  660. #endif
  661.  
  662.       worse = 0;
  663.       better = 0;
  664.  
  665.       for (j = 0; j < ncriteria; j++) {
  666.         int cap, cvalue, fbvalue;
  667.  
  668.         cap = criteria[j].capability;
  669.         cvalue = criteria[j].value;
  670.         if (cap == NUM) {
  671.           fbvalue = numok;
  672.         } else {
  673.           fbvalue = fbmodes[i].cap[cap];
  674.         }
  675. #ifdef TEST
  676.         if (verbose)
  677.           printf("  %s %s %d to %d\n",
  678.             capstr[cap], compstr[criteria[j].comparison], cvalue, fbvalue);
  679. #endif
  680.         switch (criteria[j].comparison) {
  681.         case EQ:
  682.           result = cvalue == fbvalue;
  683.           thisScore[j] = 1;
  684.           break;
  685.         case NEQ:
  686.           result = cvalue != fbvalue;
  687.           thisScore[j] = 1;
  688.           break;
  689.         case LT:
  690.           result = fbvalue < cvalue;
  691.           thisScore[j] = fbvalue - cvalue;
  692.           break;
  693.         case GT:
  694.           result = fbvalue > cvalue;
  695.           thisScore[j] = fbvalue - cvalue;
  696.           break;
  697.         case LTE:
  698.           result = fbvalue <= cvalue;
  699.           thisScore[j] = fbvalue - cvalue;
  700.           break;
  701.         case GTE:
  702.           result = (fbvalue >= cvalue);
  703.           thisScore[j] = fbvalue - cvalue;
  704.           break;
  705.         case MIN:
  706.           result = fbvalue >= cvalue;
  707.           thisScore[j] = cvalue - fbvalue;
  708.           break;
  709.         }
  710.  
  711. #ifdef TEST
  712.         if (verbose)
  713.           printf("                result=%d   score=%d   bestScore=%d\n", result, thisScore[j], bestScore[j]);
  714. #endif
  715.  
  716.         if (result) {
  717.           if (better || thisScore[j] > bestScore[j]) {
  718.             better = 1;
  719.           } else if (thisScore[j] == bestScore[j]) {
  720.             /* Keep looking. */
  721.           } else {
  722.             goto nextFBM;
  723.           }
  724.         } else {
  725.           if (cap == NUM) {
  726.             worse = 1;
  727.           } else {
  728.             goto nextFBM;
  729.           }
  730.         }
  731.  
  732.       }
  733.  
  734.       if (better && !worse) {
  735.         found = &fbmodes[i];
  736.         for (j = 0; j < ncriteria; j++) {
  737.           bestScore[j] = thisScore[j];
  738.         }
  739.       }
  740.       numok++;
  741.  
  742.     nextFBM:;
  743.  
  744.     }
  745.   }
  746.   free(bestScore);
  747.   free(thisScore);
  748.   if (found) {
  749. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  750.     *fbc = found->fbc;
  751. #endif
  752.     return found->vi;
  753.   } else {
  754.     return NULL;
  755.   }
  756. }
  757.  
  758. static int
  759. parseCriteria(char *word, Criterion * criterion, int *mask,
  760.   Bool * allowDoubleAsSingle)
  761. {
  762.   char *cstr, *vstr, *response;
  763.   int comparator, value;
  764.   int rgb, rgba, acc, acca, count, i;
  765.  
  766.   cstr = strpbrk(word, "=><!~");
  767.   if (cstr) {
  768.     switch (cstr[0]) {
  769.     case '=':
  770.       comparator = EQ;
  771.       vstr = &cstr[1];
  772.       break;
  773.     case '~':
  774.       comparator = MIN;
  775.       vstr = &cstr[1];
  776.       break;
  777.     case '>':
  778.       if (cstr[1] == '=') {
  779.         comparator = GTE;
  780.         vstr = &cstr[2];
  781.       } else {
  782.         comparator = GT;
  783.         vstr = &cstr[1];
  784.       }
  785.       break;
  786.     case '<':
  787.       if (cstr[1] == '=') {
  788.         comparator = LTE;
  789.         vstr = &cstr[2];
  790.       } else {
  791.         comparator = LT;
  792.         vstr = &cstr[1];
  793.       }
  794.       break;
  795.     case '!':
  796.       if (cstr[1] == '=') {
  797.         comparator = NEQ;
  798.         vstr = &cstr[2];
  799.       } else {
  800.         return -1;
  801.       }
  802.       break;
  803.     default:
  804.       return -1;
  805.     }
  806.     value = (int) strtol(vstr, &response, 0);
  807.     if (response == vstr) {
  808.       /* Not a valid number. */
  809.       return -1;
  810.     }
  811.     *cstr = '\0';
  812.   } else {
  813.     comparator = NONE;
  814.   }
  815.   switch (word[0]) {
  816.   case 'a':
  817.     if (!strcmp(word, "alpha")) {
  818.       criterion[0].capability = ALPHA_SIZE;
  819.       if (comparator == NONE) {
  820.         criterion[0].comparison = GTE;
  821.         criterion[0].value = 1;
  822.       } else {
  823.         criterion[0].comparison = comparator;
  824.         criterion[0].value = value;
  825.       }
  826.       *mask |= (1 << RGBA);
  827.       *mask |= (1 << ALPHA_SIZE);
  828.       *mask |= (1 << RGBA_MODE);
  829.       return 1;
  830.     }
  831.     acca = !strcmp(word, "acca");
  832.     acc = !strcmp(word, "acc");
  833.     if (acc || acca) {
  834.       criterion[0].capability = ACCUM_RED_SIZE;
  835.       criterion[1].capability = ACCUM_GREEN_SIZE;
  836.       criterion[2].capability = ACCUM_BLUE_SIZE;
  837.       criterion[3].capability = ACCUM_ALPHA_SIZE;
  838.       if (acca) {
  839.         count = 4;
  840.       } else {
  841.         count = 3;
  842.         criterion[3].comparison = MIN;
  843.         criterion[3].value = 0;
  844.       }
  845.       if (comparator == NONE) {
  846.         comparator = GTE;
  847.         value = 8;
  848.       }
  849.       for (i = 0; i < count; i++) {
  850.         criterion[i].comparison = comparator;
  851.         criterion[i].value = value;
  852.       }
  853.       *mask |= (1 << ACCUM_RED_SIZE);
  854.       return 4;
  855.     }
  856.     if (!strcmp(word, "auxbufs")) {
  857.       criterion[0].capability = AUX_BUFFERS;
  858.       if (comparator == NONE) {
  859.         criterion[0].comparison = MIN;
  860.         criterion[0].value = 1;
  861.       } else {
  862.         criterion[0].comparison = comparator;
  863.         criterion[0].value = value;
  864.       }
  865.       *mask |= (1 << AUX_BUFFERS);
  866.       return 1;
  867.     }
  868.     return -1;
  869.   case 'b':
  870.     if (!strcmp(word, "blue")) {
  871.       criterion[0].capability = BLUE_SIZE;
  872.       if (comparator == NONE) {
  873.         criterion[0].comparison = GTE;
  874.         criterion[0].value = 1;
  875.       } else {
  876.         criterion[0].comparison = comparator;
  877.         criterion[0].value = value;
  878.       }
  879.       *mask |= (1 << RGBA);
  880.       *mask |= (1 << RGBA_MODE);
  881.       return 1;
  882.     }
  883.     if (!strcmp(word, "buffer")) {
  884.       criterion[0].capability = BUFFER_SIZE;
  885.       if (comparator == NONE) {
  886.         criterion[0].comparison = GTE;
  887.         criterion[0].value = 1;
  888.       } else {
  889.         criterion[0].comparison = comparator;
  890.         criterion[0].value = value;
  891.       }
  892.       return 1;
  893.     }
  894.     return -1;
  895.   case 'c':
  896.     if (!strcmp(word, "conformant")) {
  897.       criterion[0].capability = CONFORMANT;
  898.       if (comparator == NONE) {
  899.         criterion[0].comparison = EQ;
  900.         criterion[0].value = 1;
  901.       } else {
  902.         criterion[0].comparison = comparator;
  903.         criterion[0].value = value;
  904.       }
  905.       *mask |= (1 << CONFORMANT);
  906.       return 1;
  907.     }
  908.     return -1;
  909.   case 'd':
  910.     if (!strcmp(word, "depth")) {
  911.       criterion[0].capability = DEPTH_SIZE;
  912.       if (comparator == NONE) {
  913.         criterion[0].comparison = GTE;
  914.         criterion[0].value = 12;
  915.       } else {
  916.         criterion[0].comparison = comparator;
  917.         criterion[0].value = value;
  918.       }
  919.       *mask |= (1 << DEPTH_SIZE);
  920.       return 1;
  921.     }
  922.     if (!strcmp(word, "double")) {
  923.       criterion[0].capability = DOUBLEBUFFER;
  924.       if (comparator == NONE) {
  925.         criterion[0].comparison = EQ;
  926.         criterion[0].value = 1;
  927.       } else {
  928.         criterion[0].comparison = comparator;
  929.         criterion[0].value = value;
  930.       }
  931.       *mask |= (1 << DOUBLEBUFFER);
  932.       return 1;
  933.     }
  934.     return -1;
  935.   case 'g':
  936.     if (!strcmp(word, "green")) {
  937.       criterion[0].capability = GREEN_SIZE;
  938.       if (comparator == NONE) {
  939.         criterion[0].comparison = GTE;
  940.         criterion[0].value = 1;
  941.       } else {
  942.         criterion[0].comparison = comparator;
  943.         criterion[0].value = value;
  944.       }
  945.       *mask |= (1 << RGBA);
  946.       *mask |= (1 << RGBA_MODE);
  947.       return 1;
  948.     }
  949.     return -1;
  950.   case 'i':
  951.     if (!strcmp(word, "index")) {
  952.       criterion[0].capability = RGBA;
  953.       criterion[0].comparison = EQ;
  954.       criterion[0].value = 0;
  955.       *mask |= (1 << RGBA);
  956.       *mask |= (1 << CI_MODE);
  957.       criterion[1].capability = BUFFER_SIZE;
  958.       if (comparator == NONE) {
  959.         criterion[1].comparison = GTE;
  960.         criterion[1].value = 1;
  961.       } else {
  962.         criterion[1].comparison = comparator;
  963.         criterion[1].value = value;
  964.       }
  965.       return 2;
  966.     }
  967.     return -1;
  968.   case 'l':
  969.     if (!strcmp(word, "luminance")) {
  970.       criterion[0].capability = RGBA;
  971.       criterion[0].comparison = EQ;
  972.       criterion[0].value = 1;
  973.  
  974.       criterion[1].capability = RED_SIZE;
  975.       if (comparator == NONE) {
  976.         criterion[1].comparison = GTE;
  977.         criterion[1].value = 1;
  978.       } else {
  979.         criterion[1].comparison = comparator;
  980.         criterion[1].value = value;
  981.       }
  982.  
  983.       criterion[2].capability = GREEN_SIZE;
  984.       criterion[2].comparison = EQ;
  985.       criterion[2].value = 0;
  986.  
  987.       criterion[3].capability = BLUE_SIZE;
  988.       criterion[3].comparison = EQ;
  989.       criterion[3].value = 0;
  990.  
  991.       *mask |= (1 << RGBA);
  992.       *mask |= (1 << RGBA_MODE);
  993.       *mask |= (1 << LUMINANCE_MODE);
  994.       return 4;
  995.     }
  996.     return -1;
  997.   case 'n':
  998.     if (!strcmp(word, "num")) {
  999.       criterion[0].capability = NUM;
  1000.       if (comparator == NONE) {
  1001.         return -1;
  1002.       } else {
  1003.         criterion[0].comparison = comparator;
  1004.         criterion[0].value = value;
  1005.         return 1;
  1006.       }
  1007.     }
  1008.     return -1;
  1009.   case 'r':
  1010.     if (!strcmp(word, "red")) {
  1011.       criterion[0].capability = RED_SIZE;
  1012.       if (comparator == NONE) {
  1013.         criterion[0].comparison = GTE;
  1014.         criterion[0].value = 1;
  1015.       } else {
  1016.         criterion[0].comparison = comparator;
  1017.         criterion[0].value = value;
  1018.       }
  1019.       *mask |= (1 << RGBA);
  1020.       *mask |= (1 << RGBA_MODE);
  1021.       return 1;
  1022.     }
  1023.     rgba = !strcmp(word, "rgba");
  1024.     rgb = !strcmp(word, "rgb");
  1025.     if (rgb || rgba) {
  1026.       criterion[0].capability = RGBA;
  1027.       criterion[0].comparison = EQ;
  1028.       criterion[0].value = 1;
  1029.  
  1030.       criterion[1].capability = RED_SIZE;
  1031.       criterion[2].capability = GREEN_SIZE;
  1032.       criterion[3].capability = BLUE_SIZE;
  1033.       criterion[4].capability = ALPHA_SIZE;
  1034.       if (rgba) {
  1035.         count = 5;
  1036.       } else {
  1037.         count = 4;
  1038.         criterion[4].comparison = MIN;
  1039.         criterion[4].value = 0;
  1040.       }
  1041.       if (comparator == NONE) {
  1042.         comparator = GTE;
  1043.         value = 1;
  1044.       }
  1045.       for (i = 1; i < count; i++) {
  1046.         criterion[i].comparison = comparator;
  1047.         criterion[i].value = value;
  1048.       }
  1049.       *mask |= (1 << RGBA);
  1050.       *mask |= (1 << RGBA_MODE);
  1051.       return 5;
  1052.     }
  1053.     return -1;
  1054.   case 's':
  1055.     if (!strcmp(word, "stencil")) {
  1056.       criterion[0].capability = STENCIL_SIZE;
  1057.       if (comparator == NONE) {
  1058.         criterion[0].comparison = MIN;
  1059.         criterion[0].value = 1;
  1060.       } else {
  1061.         criterion[0].comparison = comparator;
  1062.         criterion[0].value = value;
  1063.       }
  1064.       *mask |= (1 << STENCIL_SIZE);
  1065.       return 1;
  1066.     }
  1067.     if (!strcmp(word, "single")) {
  1068.       criterion[0].capability = DOUBLEBUFFER;
  1069.       if (comparator == NONE) {
  1070.         criterion[0].comparison = EQ;
  1071.         criterion[0].value = 0;
  1072.         *allowDoubleAsSingle = True;
  1073.         *mask |= (1 << DOUBLEBUFFER);
  1074.         return 1;
  1075.       } else {
  1076.         return -1;
  1077.       }
  1078.     }
  1079.     if (!strcmp(word, "stereo")) {
  1080.       criterion[0].capability = STEREO;
  1081.       if (comparator == NONE) {
  1082.         criterion[0].comparison = EQ;
  1083.         criterion[0].value = 1;
  1084.       } else {
  1085.         criterion[0].comparison = comparator;
  1086.         criterion[0].value = value;
  1087.       }
  1088.       *mask |= (1 << STEREO);
  1089.       return 1;
  1090.     }
  1091.     if (!strcmp(word, "samples")) {
  1092.       criterion[0].capability = SAMPLES;
  1093.       if (comparator == NONE) {
  1094.         criterion[0].comparison = LTE;
  1095.         criterion[0].value = 4;
  1096.       } else {
  1097.         criterion[0].comparison = comparator;
  1098.         criterion[0].value = value;
  1099.       }
  1100.       *mask |= (1 << SAMPLES);
  1101.       return 1;
  1102.     }
  1103.     if (!strcmp(word, "slow")) {
  1104.       criterion[0].capability = SLOW;
  1105.       if (comparator == NONE) {
  1106.         /* Just "slow" means permit fast visuals, but accept
  1107.            slow ones in preference. Presumably the slow ones
  1108.            must be higher quality or something else desirable. */
  1109.         criterion[0].comparison = GTE;
  1110.         criterion[0].value = 0;
  1111.       } else {
  1112.         criterion[0].comparison = comparator;
  1113.         criterion[0].value = value;
  1114.       }
  1115.       *mask |= (1 << SLOW);
  1116.       return 1;
  1117.     }
  1118.     return -1;
  1119. #if defined(_WIN32)
  1120.   case 'w':
  1121.     if (!strcmp(word, "win32pfd")) {
  1122.       criterion[0].capability = XVISUAL;
  1123.       if (comparator == NONE) {
  1124.         return -1;
  1125.       } else {
  1126.         criterion[0].comparison = comparator;
  1127.         criterion[0].value = value;
  1128.         return 1;
  1129.       }
  1130.     }
  1131.     return -1;
  1132. #endif
  1133. #if !defined(_WIN32)
  1134.   case 'x':
  1135.     if (!strcmp(word, "xvisual")) {
  1136.       if (comparator == NONE) {
  1137.         return -1;
  1138.       } else {
  1139.         criterion[0].capability = XVISUAL;
  1140.         criterion[0].comparison = comparator;
  1141.         criterion[0].value = value;
  1142.         /* Set everything in "mask" so that no default criteria
  1143.            get used.  Assume the program really wants the
  1144.            xvisual specified. */
  1145.         *mask |= ~0;
  1146.         return 1;
  1147.       }
  1148.     }
  1149.     /* Be a little over-eager to fill in the comparison and
  1150.        value so we won't have to replicate the code after each
  1151.        string match. */
  1152.     if (comparator == NONE) {
  1153.       criterion[0].comparison = EQ;
  1154.       criterion[0].value = 1;
  1155.     } else {
  1156.       criterion[0].comparison = comparator;
  1157.       criterion[0].value = value;
  1158.     }
  1159.  
  1160.     if (!strcmp(word, "xstaticgray")) {
  1161.       criterion[0].capability = XSTATICGRAY;
  1162.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1163.                                        class selected. */
  1164.       return 1;
  1165.     }
  1166.     if (!strcmp(word, "xgrayscale")) {
  1167.       criterion[0].capability = XGRAYSCALE;
  1168.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1169.                                        class selected. */
  1170.       return 1;
  1171.     }
  1172.     if (!strcmp(word, "xstaticcolor")) {
  1173.       criterion[0].capability = XSTATICCOLOR;
  1174.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1175.                                        class selected. */
  1176.       return 1;
  1177.     }
  1178.     if (!strcmp(word, "xpseudocolor")) {
  1179.       criterion[0].capability = XPSEUDOCOLOR;
  1180.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1181.                                        class selected. */
  1182.       return 1;
  1183.     }
  1184.     if (!strcmp(word, "xtruecolor")) {
  1185.       criterion[0].capability = XTRUECOLOR;
  1186.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1187.                                        class selected. */
  1188.       return 1;
  1189.     }
  1190.     if (!strcmp(word, "xdirectcolor")) {
  1191.       criterion[0].capability = XDIRECTCOLOR;
  1192.       *mask |= (1 << XSTATICGRAY);  /* Indicates _any_ visual
  1193.                                        class selected. */
  1194.       return 1;
  1195.     }
  1196.     return -1;
  1197. #endif
  1198.   default:
  1199.     return -1;
  1200.   }
  1201. }
  1202.  
  1203. static Criterion *
  1204. parseModeString(char *mode, int *ncriteria, Bool * allowDoubleAsSingle,
  1205.   Criterion * requiredCriteria, int nRequired, int requiredMask)
  1206. {
  1207.   Criterion *criteria = NULL;
  1208.   int n, mask, parsed, i;
  1209.   char *copy, *word;
  1210.  
  1211.   *allowDoubleAsSingle = False;
  1212.   copy = __glutStrdup(mode);
  1213.   /* Attempt to estimate how many criteria entries should be
  1214.      needed. */
  1215.   n = 0;
  1216.   word = strtok(copy, " \t");
  1217.   while (word) {
  1218.     n++;
  1219.     word = strtok(NULL, " \t");
  1220.   }
  1221.   /* Overestimate by 4 times ("rgba" might add four criteria
  1222.      entries) plus add in possible defaults plus space for
  1223.      required criteria. */
  1224.   criteria = (Criterion *) malloc((4 * n + 30 + nRequired) * sizeof(Criterion));
  1225.   if (!criteria) {
  1226.     __glutFatalError("out of memory.");
  1227.   }
  1228.  
  1229.   /* Re-copy the copy of the mode string. */
  1230.   strcpy(copy, mode);
  1231.  
  1232.   /* First add the required criteria (these match at the
  1233.      highest priority). Typically these will be used to force a
  1234.      specific level (layer), transparency, and/or visual type. */
  1235.   mask = requiredMask;
  1236.   for (i = 0; i < nRequired; i++) {
  1237.     criteria[i] = requiredCriteria[i];
  1238.   }
  1239.   n = nRequired;
  1240.  
  1241.   word = strtok(copy, " \t");
  1242.   while (word) {
  1243.     parsed = parseCriteria(word, &criteria[n], &mask, allowDoubleAsSingle);
  1244.     if (parsed >= 0) {
  1245.       n += parsed;
  1246.     } else {
  1247.       __glutWarning("Unrecognized display string word: %s (ignoring)\n", word);
  1248.     }
  1249.     word = strtok(NULL, " \t");
  1250.   }
  1251.  
  1252. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  1253.   if (__glutIsSupportedByGLX("GLX_SGIS_multisample")) {
  1254.     if (!(mask & (1 << SAMPLES))) {
  1255.       criteria[n].capability = SAMPLES;
  1256.       criteria[n].comparison = EQ;
  1257.       criteria[n].value = 0;
  1258.       n++;
  1259.     } else {
  1260.       /* Multisample visuals are marked nonconformant.  If
  1261.          multisampling was requeste and no conformant
  1262.          preference was set, assume that we will settle for a
  1263.          non-conformant visual to get multisampling. */
  1264.       if (!(mask & (1 << CONFORMANT))) {
  1265.         criteria[n].capability = CONFORMANT;
  1266.         criteria[n].comparison = MIN;
  1267.         criteria[n].value = 0;
  1268.         n++;
  1269.         mask |= (1 << CONFORMANT);
  1270.       }
  1271.     }
  1272.   }
  1273. #endif
  1274. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
  1275.   if (__glutIsSupportedByGLX("GLX_EXT_visual_info")) {
  1276.     if (!(mask & (1 << TRANSPARENT))) {
  1277.       criteria[n].capability = TRANSPARENT;
  1278.       criteria[n].comparison = EQ;
  1279.       criteria[n].value = 0;
  1280.       n++;
  1281.     }
  1282.   }
  1283. #endif
  1284. #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
  1285.   if (__glutIsSupportedByGLX("GLX_EXT_visual_rating")) {
  1286.     if (!(mask & (1 << SLOW))) {
  1287.       criteria[n].capability = SLOW;
  1288.       criteria[n].comparison = EQ;
  1289.       criteria[n].value = 0;
  1290.       n++;
  1291.     }
  1292.     if (!(mask & (1 << CONFORMANT))) {
  1293.       criteria[n].capability = CONFORMANT;
  1294.       criteria[n].comparison = EQ;
  1295.       criteria[n].value = 1;
  1296.       n++;
  1297.     }
  1298.   }
  1299. #endif
  1300.   if (!(mask & (1 << ACCUM_RED_SIZE))) {
  1301.     criteria[n].capability = ACCUM_RED_SIZE;
  1302.     criteria[n].comparison = MIN;
  1303.     criteria[n].value = 0;
  1304.     criteria[n + 1].capability = ACCUM_GREEN_SIZE;
  1305.     criteria[n + 1].comparison = MIN;
  1306.     criteria[n + 1].value = 0;
  1307.     criteria[n + 2].capability = ACCUM_BLUE_SIZE;
  1308.     criteria[n + 2].comparison = MIN;
  1309.     criteria[n + 2].value = 0;
  1310.     criteria[n + 3].capability = ACCUM_ALPHA_SIZE;
  1311.     criteria[n + 3].comparison = MIN;
  1312.     criteria[n + 3].value = 0;
  1313.     n += 4;
  1314.   }
  1315.   if (!(mask & (1 << AUX_BUFFERS))) {
  1316.     criteria[n].capability = AUX_BUFFERS;
  1317.     criteria[n].comparison = MIN;
  1318.     criteria[n].value = 0;
  1319.     n++;
  1320.   }
  1321.   if (!(mask & (1 << RGBA))) {
  1322.     criteria[n].capability = RGBA;
  1323.     criteria[n].comparison = EQ;
  1324.     criteria[n].value = 1;
  1325.     criteria[n + 1].capability = RED_SIZE;
  1326.     criteria[n + 1].comparison = GTE;
  1327.     criteria[n + 1].value = 1;
  1328.     criteria[n + 2].capability = GREEN_SIZE;
  1329.     criteria[n + 2].comparison = GTE;
  1330.     criteria[n + 2].value = 1;
  1331.     criteria[n + 3].capability = BLUE_SIZE;
  1332.     criteria[n + 3].comparison = GTE;
  1333.     criteria[n + 3].value = 1;
  1334.     criteria[n + 4].capability = ALPHA_SIZE;
  1335.     criteria[n + 4].comparison = MIN;
  1336.     criteria[n + 4].value = 0;
  1337.     n += 5;
  1338.     mask |= (1 << RGBA_MODE);
  1339.   }
  1340. #if !defined(_WIN32)
  1341.   if (!(mask & (1 << XSTATICGRAY))) {
  1342.     assert(isMesaGLX != -1);
  1343.     if ((mask & (1 << RGBA_MODE)) && !isMesaGLX) {
  1344.       /* Normally, request an RGBA mode visual be TrueColor,
  1345.          except in the case of Mesa where we trust Mesa (and
  1346.          other code in GLUT) to handle any type of RGBA visual
  1347.          reasonably. */
  1348.       if (mask & (1 << LUMINANCE_MODE)) {
  1349.     /* If RGBA luminance was requested, actually go for
  1350.        a StaticGray visual. */
  1351.         criteria[n].capability = XSTATICGRAY;
  1352.       } else {
  1353.         criteria[n].capability = XTRUECOLOR;
  1354.       }
  1355.       criteria[n].value = 1;
  1356.       criteria[n].comparison = EQ;
  1357.  
  1358.       n++;
  1359.     }
  1360.     if (mask & (1 << CI_MODE)) {
  1361.       criteria[n].capability = XPSEUDOCOLOR;
  1362.       criteria[n].value = 1;
  1363.       criteria[n].comparison = EQ;
  1364.       n++;
  1365.     }
  1366.   }
  1367. #endif
  1368.   if (!(mask & (1 << STEREO))) {
  1369.     criteria[n].capability = STEREO;
  1370.     criteria[n].comparison = EQ;
  1371.     criteria[n].value = 0;
  1372.     n++;
  1373.   }
  1374.   if (!(mask & (1 << DOUBLEBUFFER))) {
  1375.     criteria[n].capability = DOUBLEBUFFER;
  1376.     criteria[n].comparison = EQ;
  1377.     criteria[n].value = 0;
  1378.     *allowDoubleAsSingle = True;
  1379.     n++;
  1380.   }
  1381.   if (!(mask & (1 << DEPTH_SIZE))) {
  1382.     criteria[n].capability = DEPTH_SIZE;
  1383.     criteria[n].comparison = MIN;
  1384.     criteria[n].value = 0;
  1385.     n++;
  1386.   }
  1387.   if (!(mask & (1 << STENCIL_SIZE))) {
  1388.     criteria[n].capability = STENCIL_SIZE;
  1389.     criteria[n].comparison = MIN;
  1390.     criteria[n].value = 0;
  1391.     n++;
  1392.   }
  1393.   if (!(mask & (1 << LEVEL))) {
  1394.     criteria[n].capability = LEVEL;
  1395.     criteria[n].comparison = EQ;
  1396.     criteria[n].value = 0;
  1397.     n++;
  1398.   }
  1399.   if (n) {
  1400.     /* Since over-estimated the size needed; squeeze it down to
  1401.        reality. */
  1402.     criteria = (Criterion *) realloc(criteria, n * sizeof(Criterion));
  1403.     if (!criteria) {
  1404.       /* Should never happen since should be shrinking down! */
  1405.       __glutFatalError("out of memory.");
  1406.     }
  1407.   } else {
  1408.     /* For portability, avoid "realloc(ptr,0)" call. */
  1409.     free(criteria);
  1410.     criteria = NULL;
  1411.   }
  1412.  
  1413.   free(copy);
  1414.   *ncriteria = n;
  1415.   return criteria;
  1416. }
  1417.  
  1418. static FrameBufferMode *fbmodes = NULL;
  1419. static int nfbmodes = 0;
  1420.  
  1421. static XVisualInfo *
  1422. getVisualInfoFromString(char *string, Bool * treatAsSingle,
  1423.   Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc)
  1424. {
  1425.   Criterion *criteria;
  1426.   XVisualInfo *visinfo;
  1427.   Bool allowDoubleAsSingle;
  1428.   int ncriteria, i;
  1429.  
  1430.   if (!fbmodes) {
  1431.     fbmodes = loadVisuals(&nfbmodes);
  1432.   }
  1433.   criteria = parseModeString(string, &ncriteria,
  1434.     &allowDoubleAsSingle, requiredCriteria, nRequired, requiredMask);
  1435.   if (criteria == NULL) {
  1436.     __glutWarning("failed to parse mode string");
  1437.     return NULL;
  1438.   }
  1439. #ifdef TEST
  1440.   printCriteria(criteria, ncriteria);
  1441. #endif
  1442.   visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
  1443.   if (visinfo) {
  1444.     *treatAsSingle = 0;
  1445.   } else {
  1446.     if (allowDoubleAsSingle) {
  1447.       /* Rewrite criteria so that we now look for a double
  1448.          buffered visual which will then get treated as a
  1449.          single buffered visual. */
  1450.       for (i = 0; i < ncriteria; i++) {
  1451.         if (criteria[i].capability == DOUBLEBUFFER
  1452.           && criteria[i].comparison == EQ
  1453.           && criteria[i].value == 0) {
  1454.           criteria[i].value = 1;
  1455.         }
  1456.       }
  1457.       visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
  1458.       if (visinfo) {
  1459.         *treatAsSingle = 1;
  1460.       }
  1461.     }
  1462.   }
  1463.   free(criteria);
  1464.  
  1465.   if (visinfo) {
  1466. #if defined(_WIN32)
  1467.     /* We could have a valid pixel format for drawing to a
  1468.        bitmap. However, we don't want to draw into a bitmap, we 
  1469.        need one that can be used with a window, so make sure
  1470.        that this is true. */
  1471.     if (!(visinfo->dwFlags & PFD_DRAW_TO_WINDOW))
  1472.       return NULL;
  1473. #endif
  1474.     return visinfo;
  1475.   } else {
  1476.     return NULL;
  1477.   }
  1478. }
  1479.  
  1480. /* CENTRY */
  1481. void APIENTRY
  1482. glutInitDisplayString(const char *string)
  1483. {
  1484. #ifdef _WIN32
  1485.   XHDC = GetDC(GetDesktopWindow());
  1486. #endif
  1487.  
  1488.   __glutDetermineVisualFromString = getVisualInfoFromString;
  1489.   if (__glutDisplayString) {
  1490.     free(__glutDisplayString);
  1491.   }
  1492.   if (string) {
  1493.     __glutDisplayString = __glutStrdup(string);
  1494.     if (!__glutDisplayString)
  1495.       __glutFatalError("out of memory.");
  1496.   } else {
  1497.     __glutDisplayString = NULL;
  1498.   }
  1499. }
  1500. /* ENDCENTRY */
  1501.  
  1502. #ifdef TEST
  1503.  
  1504. Criterion requiredWindowCriteria[] =
  1505. {
  1506.   {LEVEL, EQ, 0},
  1507.   {TRANSPARENT, EQ, 0}
  1508. };
  1509. int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
  1510. int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
  1511.  
  1512. Criterion requiredOverlayCriteria[] =
  1513. {
  1514.   {LEVEL, EQ, 1},
  1515.   {TRANSPARENT, EQ, 1},
  1516.   {XPSEUDOCOLOR, EQ, 1},
  1517.   {RGBA, EQ, 0},
  1518.   {BUFFER_SIZE, GTE, 1}
  1519. };
  1520. int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
  1521. int requiredOverlayCriteriaMask =
  1522. (1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
  1523.  
  1524. int
  1525. main(int argc, char **argv)
  1526. {
  1527.   Display *dpy;
  1528.   XVisualInfo *vinfo;
  1529.   Bool treatAsSingle;
  1530.   char *str, buffer[1024];
  1531.   int tty = isatty(fileno(stdin));
  1532.   int overlay = 0, showconfig = 0;
  1533. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  1534.   GLXFBConfigSGIX fbc;
  1535. #else
  1536.   void *fbc;
  1537. #endif
  1538.  
  1539. #if !defined(_WIN32)
  1540.   dpy = XOpenDisplay(NULL);
  1541.   if (dpy == NULL) {
  1542.     printf("Could not connect to X server\n");
  1543.     exit(1);
  1544.   }
  1545.   __glutDisplay = dpy;
  1546.   __glutScreen = DefaultScreen(__glutDisplay);
  1547. #endif
  1548.   while (!feof(stdin)) {
  1549.     if (tty)
  1550.       printf("dstr> ");
  1551.     str = gets(buffer);
  1552.     if (str) {
  1553.       printf("\n");
  1554.       if (!strcmp("v", str)) {
  1555.         verbose = 1 - verbose;
  1556.         printf("verbose = %d\n\n", verbose);
  1557.       } else if (!strcmp("s", str)) {
  1558.         showconfig = 1 - showconfig;
  1559.         printf("showconfig = %d\n\n", showconfig);
  1560.       } else if (!strcmp("o", str)) {
  1561.         overlay = 1 - overlay;
  1562.         printf("overlay = %d\n\n", overlay);
  1563.       } else {
  1564.         if (overlay) {
  1565.           vinfo = getVisualInfoFromString(str, &treatAsSingle,
  1566.             requiredOverlayCriteria, numRequiredOverlayCriteria, requiredOverlayCriteriaMask, (void**) &fbc);
  1567.         } else {
  1568.           vinfo = getVisualInfoFromString(str, &treatAsSingle,
  1569.             requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, (void**) &fbc);
  1570.         }
  1571.         if (vinfo) {
  1572.           printf("\n");
  1573.           if (!tty)
  1574.             printf("Display string: %s", str);
  1575. #ifdef _WIN32
  1576.           printf("Visual = 0x%x\n", 0);
  1577. #else
  1578.           printf("Visual = 0x%x%s\n", vinfo->visualid, fbc ? " (needs FBC)" : "");
  1579. #endif
  1580.           if (treatAsSingle) {
  1581.             printf("Treat as SINGLE.\n");
  1582.           }
  1583.           if (showconfig) {
  1584.             int glxCapable, bufferSize, level, renderType, doubleBuffer,
  1585.               stereo, auxBuffers, redSize, greenSize, blueSize,
  1586.               alphaSize, depthSize, stencilSize, acRedSize, acGreenSize,
  1587.               acBlueSize, acAlphaSize;
  1588.  
  1589.             glXGetConfig(dpy, vinfo, GLX_BUFFER_SIZE, &bufferSize);
  1590.             glXGetConfig(dpy, vinfo, GLX_LEVEL, &level);
  1591.             glXGetConfig(dpy, vinfo, GLX_RGBA, &renderType);
  1592.             glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &doubleBuffer);
  1593.             glXGetConfig(dpy, vinfo, GLX_STEREO, &stereo);
  1594.             glXGetConfig(dpy, vinfo, GLX_AUX_BUFFERS, &auxBuffers);
  1595.             glXGetConfig(dpy, vinfo, GLX_RED_SIZE, &redSize);
  1596.             glXGetConfig(dpy, vinfo, GLX_GREEN_SIZE, &greenSize);
  1597.             glXGetConfig(dpy, vinfo, GLX_BLUE_SIZE, &blueSize);
  1598.             glXGetConfig(dpy, vinfo, GLX_ALPHA_SIZE, &alphaSize);
  1599.             glXGetConfig(dpy, vinfo, GLX_DEPTH_SIZE, &depthSize);
  1600.             glXGetConfig(dpy, vinfo, GLX_STENCIL_SIZE, &stencilSize);
  1601.             glXGetConfig(dpy, vinfo, GLX_ACCUM_RED_SIZE, &acRedSize);
  1602.             glXGetConfig(dpy, vinfo, GLX_ACCUM_GREEN_SIZE, &acGreenSize);
  1603.             glXGetConfig(dpy, vinfo, GLX_ACCUM_BLUE_SIZE, &acBlueSize);
  1604.             glXGetConfig(dpy, vinfo, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize);
  1605.             printf("RGBA = (%d, %d, %d, %d)\n", redSize, greenSize, blueSize, alphaSize);
  1606.             printf("acc  = (%d, %d, %d, %d)\n", acRedSize, acGreenSize, acBlueSize, acAlphaSize);
  1607.             printf("db   = %d\n", doubleBuffer);
  1608.             printf("str  = %d\n", stereo);
  1609.             printf("aux  = %d\n", auxBuffers);
  1610.             printf("lvl  = %d\n", level);
  1611.             printf("buf  = %d\n", bufferSize);
  1612.             printf("rgba = %d\n", renderType);
  1613.             printf("z    = %d\n", depthSize);
  1614.             printf("s    = %d\n", stencilSize);
  1615.           }
  1616.         } else {
  1617.           printf("\n");
  1618.           printf("No match.\n");
  1619.         }
  1620.         printf("\n");
  1621.       }
  1622.     }
  1623.   }
  1624.   printf("\n");
  1625.   return 0;
  1626. }
  1627. #endif
  1628.